home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Demos / ByCompany / TipTop_Software / TipTop / Supplement / src / Z126 / sz.c < prev    next >
Text File  |  1994-05-08  |  32KB  |  1,515 lines

  1. #define VERSION "sz 1.36 08-31-87"
  2. #define PUBDIR "/usr/spool/uucppublic"
  3.  
  4. /*% cc -M0 -Ox -K -i -DNFGVMIN -DREADCHECK sz.c -lx -o sz; size sz
  5.  *
  6.  * sz.c By Chuck Forsberg
  7.  *
  8.  *    cc -O sz.c -o sz        USG (SYS III/V) Unix
  9.  *    cc -O -DSVR2 sz.c -o sz        Sys V Release 2 with non-blocking input
  10.  *                    Define to allow reverse channel checking
  11.  *    cc -O -DV7  sz.c -o sz        Unix Version 7, 2.8 - 4.3 BSD
  12.  *
  13.  *    cc -O -K -i -DNFGVMIN -DREADCHECK sz.c -lx -o sz    Xenix
  14.  *
  15.  *    ln sz sb            **** All versions ****
  16.  *    ln sz sx            **** All versions ****
  17.  *
  18.  *
  19.  *  ******* Some systems (Venix, Coherent, Regulus) do not *******
  20.  *  ******* support tty raw mode read(2) identically to    *******
  21.  *  ******* Unix. ONEREAD must be defined to force one     *******
  22.  *  ******* character reads for these systems.           *******
  23.  *
  24.  * A program for Unix to send files and commands to computers running
  25.  *  Professional-YAM, PowerCom, YAM, IMP, or programs supporting Y/XMODEM.
  26.  *
  27.  *  Sz uses buffered I/O to greatly reduce CPU time compared to UMODEM.
  28.  *
  29.  *  USG UNIX (3.0) ioctl conventions courtesy Jeff Martin
  30.  *
  31.  * 1.34 implements tx backchannel garbage count and ZCRCW after ZRPOS
  32.  * in accordance with the 7-31-87 ZMODEM Protocol Description
  33.  */
  34.  
  35. #ifdef NeXT
  36. #import <objc/objc.h>
  37. #import "TransferProgressProtocol.h"
  38. id getProgressListener();
  39. static id remote;
  40. #endif
  41.  
  42. char *substr(), *getenv();
  43.  
  44. #define LOGFILE "/tmp/szlog"
  45.  
  46. #include <stdio.h>
  47. #include <signal.h>
  48. #include <setjmp.h>
  49. #include <ctype.h>
  50.  
  51. #define PATHLEN 256
  52. #define OK 0
  53. #define FALSE 0
  54. #define TRUE 1
  55. #define ERROR (-1)
  56.  
  57. #define HOWMANY 2
  58. int Zmodem=0;        /* ZMODEM protocol requested */
  59. unsigned Baudrate;
  60. unsigned Txwindow;    /* Control the size of the transmitted window */
  61. unsigned Txwspac;    /* Spacing between zcrcq requests */
  62. unsigned Txwcnt;    /* Counter used to space ack requests */
  63. long Lrxpos;        /* Receiver's last reported offset */
  64. int Fromcu = 0;        /* Were called from cu or yam */
  65. int errors;
  66. #include "rbsb.c"    /* most of the system dependent stuff here */
  67.  
  68. /*
  69.  * Attention string to be executed by receiver to interrupt streaming data
  70.  *  when an error is detected.  A pause (0336) may be needed before the
  71.  *  ^C (03) or after it.
  72.  */
  73. #ifdef READCHECK
  74. char Myattn[] = { 0 };
  75. #else
  76. #ifdef USG
  77. char Myattn[] = { 03, 0336, 0 };
  78. #else
  79. char Myattn[] = { 0 };
  80. #endif
  81. #endif
  82.  
  83. FILE *in;
  84.  
  85. /* Ward Christensen / CP/M parameters - Don't change these! */
  86. #define ENQ 005
  87. #define CAN ('X'&037)
  88. #define XOFF ('s'&037)
  89. #define XON ('q'&037)
  90. #define SOH 1
  91. #define STX 2
  92. #define EOT 4
  93. #define ACK 6
  94. #define NAK 025
  95. #define CPMEOF 032
  96. #define WANTCRC 0103    /* send C not NAK to get crc not checksum */
  97. #define WANTG 0107    /* Send G not NAK to get nonstop batch xmsn */
  98. #define TIMEOUT (-2)
  99. #define RCDO (-3)
  100. #define RETRYMAX 10
  101. #define SECSIZ 128    /* cp/m's Magic Number record size */
  102. #define KSIZE 1024
  103.  
  104. char Lastrx;
  105. char Crcflg;
  106. int Wcsmask=0377;
  107. int Verbose=0;
  108. int Modem2=0;        /* XMODEM Protocol - don't send pathnames */
  109. int Restricted=0;    /* restricted; no /.. or ../ in filenames */
  110. int Quiet=0;        /* overrides logic that would otherwise set verbose */
  111. int Ascii=0;        /* Add CR's for brain damaged programs */
  112. int Fullname=0;        /* transmit full pathname */
  113. int Unlinkafter=0;    /* Unlink file after it is sent */
  114. int Dottoslash=0;    /* Change foo.bar.baz to foo/bar/baz */
  115. int firstsec;
  116. int errcnt=0;        /* number of files unreadable */
  117. int blklen=SECSIZ;        /* length of transmitted records */
  118. int Optiong;        /* Let it rip no wait for sector ACK's */
  119. int Noeofseen;
  120. int Totsecs;        /* total number of sectors this file */
  121. char txbuf[KSIZE];
  122. int Filcnt=0;        /* count of number of files opened */
  123. int Lfseen=0;
  124. unsigned Rxbuflen = 16384;    /* Receiver's max buffer length */
  125. int Tframlen = 0;    /* Override for tx frame length */
  126. int blkopt=0;        /* Override value for zmodem blklen */
  127. int Rxflags = 0;
  128. long bytcnt;
  129. int Wantfcs32 = TRUE;    /* want to send 32 bit FCS */
  130. char Lzconv;    /* Local ZMODEM file conversion request */
  131. char Lzmanag;    /* Local ZMODEM file management request */
  132. int Lskipnocor;
  133. char Lztrans;
  134. char zconv;        /* ZMODEM file conversion request */
  135. char zmanag;        /* ZMODEM file management request */
  136. char ztrans;        /* ZMODEM file transport request */
  137. int Command;        /* Send a command, then exit. */
  138. char *Cmdstr;        /* Pointer to the command string */
  139. int Cmdtries = 11;
  140. int Cmdack1;        /* Rx ACKs command, then do it */
  141. int Exitcode;
  142. int Testattn;        /* Force receiver to send Attn, etc with qbf. */
  143. char *qbf="The quick brown fox jumped over the lazy dog's back 1234567890\r\n";
  144. long Lastread;        /* Beginning offset of last buffer read */
  145. int Lastn;        /* Count of last buffer read or -1 */
  146. int Dontread;        /* Don't read the buffer, it's still there */
  147. long Lastsync;        /* Last offset to which we got a ZRPOS */
  148. int Beenhereb4;        /* How many times we've been ZRPOS'd same place */
  149.  
  150. jmp_buf tohere;        /* For the interrupt on RX timeout */
  151. jmp_buf intrjmp;    /* For the interrupt on RX CAN */
  152.  
  153. /* called by signal interrupt or terminate to clean things up */
  154. bibi(n)
  155. {
  156.     canit(); fflush(stdout); mode(0);
  157.     fprintf(stderr, "sz: caught signal %d; exiting\n", n);
  158. #ifdef NeXT
  159.     { char buf[50];
  160.       sprintf(buf,"Caught signal %d; exiting",n);
  161.       [remote transferMessage:buf];
  162.       sleep(1);
  163.       [remote transferEnd];
  164.     }
  165. #endif
  166.     if (n == SIGQUIT)
  167.         abort();
  168.     exit(128+n);
  169. }
  170. /* Called when Zmodem gets an interrupt (^X) */
  171. onintr()
  172. {
  173.     signal(SIGINT, SIG_IGN);
  174.     longjmp(intrjmp, -1);
  175. }
  176.  
  177.  
  178. #define sendline(c) putchar(c & Wcsmask)
  179.  
  180. #define xsendline(c) putchar(c)
  181.  
  182. flushmo()
  183. {
  184.     fflush(stdout);
  185. }
  186.  
  187. int Zctlesc;    /* Encode control characters */
  188. int Nozmodem = 0;    /* If invoked as "sb" */
  189. char *Progname = "sz";
  190. int Zrwindow = 1400;    /* RX window size (controls garbage count) */
  191. #include "zm.c"
  192.  
  193.  
  194. main(argc, argv)
  195. char *argv[];
  196. {
  197.     register char *cp;
  198.     register npats;
  199.     int agcnt; char **agcv;
  200.     char **patts;
  201.     static char xXbuf[BUFSIZ];
  202.  
  203.     if ((cp = getenv("ZNULLS")) && *cp)
  204.         Znulls = atoi(cp);
  205.     if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
  206.         Restricted=TRUE;
  207.     chkinvok(argv[0]);
  208.  
  209.     Rxtimeout = 600;
  210.     npats=0;
  211.     if (argc<2)
  212.         usage();
  213.     setbuf(stdout, xXbuf);        
  214.     while (--argc) {
  215.         cp = *++argv;
  216.         if (*cp++ == '-' && *cp) {
  217.             while ( *cp) {
  218.                 switch(*cp++) {
  219.                 case '+':
  220.                     Lzmanag = ZMAPND; break;
  221.                 case '1':
  222.                     iofd = 1; break;
  223. #ifdef CSTOPB
  224.                 case '2':
  225.                     Twostop = TRUE; break;
  226. #endif
  227.                 case '7':
  228.                     Wcsmask=0177; break;
  229.                 case 'a':
  230.                     Lzconv = ZCNL;
  231.                     Ascii = TRUE; break;
  232.                 case 'b':
  233.                     Lzconv = ZCBIN; break;
  234.                 case 'C':
  235.                     if (--argc < 1) {
  236.                         usage();
  237.                     }
  238.                     Cmdtries = atoi(*++argv);
  239.                     break;
  240.                 case 'i':
  241.                     Cmdack1 = ZCACK1;
  242.                     /* **** FALL THROUGH TO **** */
  243.                 case 'c':
  244.                     if (--argc != 1) {
  245.                         usage();
  246.                     }
  247.                     Command = TRUE;
  248.                     Cmdstr = *++argv;
  249.                     break;
  250.                 case 'd':
  251.                     ++Dottoslash;
  252.                     /* **** FALL THROUGH TO **** */
  253.                 case 'f':
  254.                     Fullname=TRUE; break;
  255.                 case 'e':
  256.                     Zctlesc = 1; break;
  257.                 case 'k':
  258.                     blklen=KSIZE; break;
  259.                 case 'L':
  260.                     if (--argc < 1) {
  261.                         usage();
  262.                     }
  263.                     blkopt = atoi(*++argv);
  264.                     if (blkopt<24 || blkopt>1024)
  265.                         usage();
  266.                     break;
  267.                 case 'l':
  268.                     if (--argc < 1) {
  269.                         usage();
  270.                     }
  271.                     Tframlen = atoi(*++argv);
  272.                     if (Tframlen<32 || Tframlen>1024)
  273.                         usage();
  274.                     break;
  275.                 case 'N':
  276.                     Lzmanag = ZMNEWL;  break;
  277.                 case 'n':
  278.                     Lzmanag = ZMNEW;  break;
  279.                 case 'o':
  280.                     Wantfcs32 = FALSE; break;
  281.                 case 'p':
  282.                     Lzmanag = ZMPROT;  break;
  283.                 case 'r':
  284.                     Lzconv = ZCRESUM;
  285.                 case 'q':
  286.                     Quiet=TRUE; Verbose=0; break;
  287.                 case 't':
  288.                     if (--argc < 1) {
  289.                         usage();
  290.                     }
  291.                     Rxtimeout = atoi(*++argv);
  292.                     if (Rxtimeout<10 || Rxtimeout>1000)
  293.                         usage();
  294.                     break;
  295.                 case 'T':
  296.                     Testattn = TRUE; break;
  297.                 case 'u':
  298.                     ++Unlinkafter; break;
  299.                 case 'v':
  300.                     ++Verbose; break;
  301.                 case 'w':
  302.                     if (--argc < 1) {
  303.                         usage();
  304.                     }
  305.                     Txwindow = atoi(*++argv);
  306.                     if (Txwindow < 256)
  307.                         Txwindow = 256;
  308.                     Txwindow = (Txwindow/64) * 64;
  309.                     Txwspac = Txwindow/4;
  310.                     if (blkopt > Txwspac
  311.                      || (!blkopt && Txwspac < 1024))
  312.                         blkopt = Txwspac;
  313.                     break;
  314.                 case 'X':
  315.                     ++Modem2; break;
  316.                 case 'Y':
  317.                     Lskipnocor = TRUE;
  318.                     /* **** FALLL THROUGH TO **** */
  319.                 case 'y':
  320.                     Lzmanag = ZMCLOB; break;
  321.                 default:
  322.                     usage();
  323.                 }
  324.             }
  325.         }
  326.         else if ( !npats && argc>0) {
  327.             if (argv[0][0]) {
  328.                 npats=argc;
  329.                 patts=argv;
  330.                 if ( !strcmp(*patts, "-"))
  331.                     iofd = 1;
  332.             }
  333.         }
  334.     }
  335.     if (npats < 1 && !Command) 
  336.         usage();
  337.     if (Verbose) {
  338.         if (freopen(LOGFILE, "a", stderr)==NULL) {
  339.             printf("Can't open log file %s\n",LOGFILE);
  340.             exit(0200);
  341.         }
  342.         setbuf(stderr, NULL);
  343.     }
  344.     if ((Fromcu=from_cu()) && !Quiet) {
  345.         if (Verbose == 0)
  346.             Verbose = 2;
  347.     }
  348.  
  349.     mode(1);
  350.  
  351.     if (signal(SIGINT, bibi) == SIG_IGN) {
  352.         signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
  353.     } else {
  354.         signal(SIGINT, bibi); signal(SIGKILL, bibi);
  355.     }
  356.     if ( !Fromcu)
  357.         signal(SIGQUIT, SIG_IGN);
  358.     signal(SIGTERM, bibi);
  359. #ifdef NeXT
  360.     remote=getProgressListener();
  361.     [remote transferBegin:Modem2?"XMODEM Send"
  362.                     :(Nozmodem?"YMODEM Send":"ZMODEM Send")];
  363.  
  364.     // Report list of files to be transferred to TipTop
  365.     if(!Command) {
  366.       int i;
  367.       struct stat f;
  368.       for(i=0;i<npats;i++) {
  369.         if(access(patts[i],4/*R_OK*/)==0 && stat(patts[i],&f)==0)
  370.           [remote transferFile:patts[i] size:f.st_size];
  371.       }
  372.     }
  373. #endif
  374.  
  375.     if ( !Modem2) {
  376.         if (!Nozmodem) {
  377.             printf("rz\r");  fflush(stdout);
  378.         }
  379.         if (!Command && !Quiet && Verbose != 1) {
  380.             fprintf(stderr, "%s: %d file%s requested:\r\n",
  381.              Progname, npats, npats>1?"s":"");
  382.             for ( agcnt=npats, agcv=patts; --agcnt>=0; ) {
  383.                 fprintf(stderr, "%s ", *agcv++);
  384.             }
  385.             fprintf(stderr, "\r\n");
  386.             printf("\r\n\bSending in Batch Mode\r\n");
  387.         }
  388.         if (!Nozmodem) {
  389.             stohdr(0L);
  390.             if (Command)
  391.                 Txhdr[ZF0] = ZCOMMAND;
  392.             zshhdr(ZRQINIT, Txhdr);
  393.         }
  394.     }
  395.     fflush(stdout);
  396.  
  397.     if (Command) {
  398.         if (getzrxinit()) {
  399.             Exitcode=0200; canit();
  400.         }
  401.         else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) {
  402.             Exitcode=0200; canit();
  403.         }
  404.     } else if (wcsend(npats, patts)==ERROR) {
  405.         Exitcode=0200;
  406.         canit();
  407.     }
  408. #ifdef NeXT
  409.     [remote transferEnd];
  410. #endif
  411.     fflush(stdout);
  412.     mode(0);
  413.     exit((errcnt != 0) | Exitcode);
  414.     /*NOTREACHED*/
  415. }
  416.  
  417. wcsend(argc, argp)
  418. char *argp[];
  419. {
  420.     register n;
  421.  
  422.     Crcflg=FALSE;
  423.     firstsec=TRUE;
  424.     bytcnt = -1;
  425.     for (n=0; n<argc; ++n) {
  426.         Totsecs = 0;
  427. #ifdef NeXT
  428.         [remote transferFileBegin:argp[n]];
  429. #endif
  430.         if (wcs(argp[n])==ERROR)
  431.             return ERROR;
  432.     }
  433.     Totsecs = 0;
  434.     if (Filcnt==0) {    /* bitch if we couldn't open ANY files */
  435.         if (1) {
  436.             Command = TRUE;
  437.             Cmdstr = "echo \"sz: Can't open any requested files\"";
  438.             if (getnak()) {
  439.                 Exitcode=0200; canit();
  440.             }
  441.             if (!Zmodem)
  442.                 canit();
  443.             else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) {
  444.                 Exitcode=0200; canit();
  445.             }
  446.             Exitcode = 1; return OK;
  447.         }
  448.         canit();
  449.         fprintf(stderr,"\r\nCan't open any requested files.\r\n");
  450.         return ERROR;
  451.     }
  452.     if (Zmodem)
  453.         saybibi();
  454.     else if ( !Modem2)
  455.         wctxpn("");
  456.     return OK;
  457. }
  458.  
  459. wcs(oname)
  460. char *oname;
  461. {
  462.     register c;
  463.     register char *p;
  464.     struct stat f;
  465.     char name[PATHLEN];
  466.  
  467.     strcpy(name, oname);
  468.  
  469.     if (Restricted) {
  470.         /* restrict pathnames to current tree or uucppublic */
  471.         if ( substr(name, "../")
  472.          || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
  473.             canit();
  474.             fprintf(stderr,"\r\nsz:\tSecurity Violation\r\n");
  475.             return ERROR;
  476.         }
  477.     }
  478.  
  479.     if ( !strcmp(oname, "-")) {
  480.         if ((p = getenv("ONAME")) && *p)
  481.             strcpy(name, p);
  482.         else
  483.             sprintf(name, "s%d.sz", getpid());
  484.         in = stdin;
  485.     }
  486.     else if ((in=fopen(oname, "r"))==NULL) {
  487.         ++errcnt;
  488.         return OK;    /* pass over it, there may be others */
  489.     }
  490.     ++Noeofseen;  Lastread = 0;  Lastn = -1; Dontread = FALSE;
  491.     /* Check for directory or block special files */
  492.     fstat(fileno(in), &f);
  493.     c = f.st_mode & S_IFMT;
  494.     if (c == S_IFDIR || c == S_IFBLK) {
  495.         fclose(in);
  496.         return OK;
  497.     }
  498.  
  499.     ++Filcnt;
  500.     switch (wctxpn(name)) {
  501.     case ERROR:
  502.         return ERROR;
  503.     case ZSKIP:
  504.         return OK;
  505.     }
  506.     if (!Zmodem && wctx(f.st_size)==ERROR)
  507.         return ERROR;
  508.     if (Unlinkafter)
  509.         unlink(oname);
  510.     return 0;
  511. }
  512.  
  513. /*
  514.  * generate and transmit pathname block consisting of
  515.  *  pathname (null terminated),
  516.  *  file length, mode time and file mode in octal
  517.  *  as provided by the Unix fstat call.
  518.  *  N.B.: modifies the passed name, may extend it!
  519.  */
  520. wctxpn(name)
  521. char *name;
  522. {
  523.     register char *p, *q;
  524.     char name2[PATHLEN];
  525.     struct stat f;
  526.  
  527.     if (Modem2) {
  528.         if ((in!=stdin) && *name && fstat(fileno(in), &f)!= -1) {
  529.             fprintf(stderr, "Sending %s, %ld blocks: ",
  530.               name, f.st_size>>7);
  531.         }
  532.         fprintf(stderr, "Give your local XMODEM receive command now.\r\n");
  533.         return OK;
  534.     }
  535.     zperr("Awaiting pathname nak for %s", *name?name:"<END>");
  536.     if ( !Zmodem)
  537.         if (getnak())
  538.             return ERROR;
  539.  
  540.     q = (char *) 0;
  541.     if (Dottoslash) {        /* change . to . */
  542.         for (p=name; *p; ++p) {
  543.             if (*p == '/')
  544.                 q = p;
  545.             else if (*p == '.')
  546.                 *(q=p) = '/';
  547.         }
  548.         if (q && strlen(++q) > 8) {    /* If name>8 chars */
  549.             q += 8;            /*   make it .ext */
  550.             strcpy(name2, q);    /* save excess of name */
  551.             *q = '.';
  552.             strcpy(++q, name2);    /* add it back */
  553.         }
  554.     }
  555.  
  556.     for (p=name, q=txbuf ; *p; )
  557.         if ((*q++ = *p++) == '/' && !Fullname)
  558.             q = txbuf;
  559.     *q++ = 0;
  560.     p=q;
  561.     while (q < (txbuf + KSIZE))
  562.         *q++ = 0;
  563.     if (!Ascii && (in!=stdin) && *name && fstat(fileno(in), &f)!= -1)
  564.         sprintf(p, "%lu %lo %o", f.st_size, f.st_mtime, f.st_mode);
  565.     /* force 1k blocks if name won't fit in 128 byte block */
  566.     if (txbuf[125])
  567.         blklen=KSIZE;
  568.     else {        /* A little goodie for IMP/KMD */
  569.         if (Zmodem)
  570.             blklen = SECSIZ;
  571.         txbuf[127] = (f.st_size + 127) >>7;
  572.         txbuf[126] = (f.st_size + 127) >>15;
  573.     }
  574.     if (Zmodem)
  575.         return zsendfile(txbuf, 1+strlen(p)+(p-txbuf));
  576.     if (wcputsec(txbuf, 0, SECSIZ)==ERROR)
  577.         return ERROR;
  578.     return OK;
  579. }
  580.  
  581. getnak()
  582. {
  583.     register firstch;
  584.  
  585.     Lastrx = 0;
  586.     for (;;) {
  587.         switch (firstch = readock(800,1)) {
  588.         case ZPAD:
  589.             if (getzrxinit())
  590.                 return ERROR;
  591.             Ascii = 0;
  592.             return FALSE;
  593.         case TIMEOUT:
  594.             zperr("Timeout on pathname");
  595.             return TRUE;
  596.         case WANTG:
  597. #ifdef USG
  598.             mode(2);    /* Set cbreak, XON/XOFF, etc. */
  599. #endif
  600.             Optiong = TRUE;
  601.             blklen=KSIZE;
  602.         case WANTCRC:
  603.             Crcflg = TRUE;
  604.         case NAK:
  605.             return FALSE;
  606.         case CAN:
  607.             if ((firstch = readock(20,1)) == CAN && Lastrx == CAN)
  608.                 return TRUE;
  609.         default:
  610.             break;
  611.         }
  612.         Lastrx = firstch;
  613.     }
  614. }
  615.  
  616.  
  617. wctx(flen)
  618. long flen;
  619. {
  620.     register int thisblklen;
  621.     register int sectnum, attempts, firstch;
  622.     long charssent;
  623.  
  624.     charssent = 0;  firstsec=TRUE;  thisblklen = blklen;
  625.     vfile("wctx:file length=%ld", flen);
  626.  
  627.     while ((firstch=readock(Rxtimeout, 2))!=NAK && firstch != WANTCRC
  628.       && firstch != WANTG && firstch!=TIMEOUT && firstch!=CAN)
  629.         ;
  630.     if (firstch==CAN) {
  631.         zperr("Receiver CANcelled");
  632.         return ERROR;
  633.     }
  634.     if (firstch==WANTCRC)
  635.         Crcflg=TRUE;
  636.     if (firstch==WANTG)
  637.         Crcflg=TRUE;
  638.     sectnum=0;
  639.     for (;;) {
  640.         if (flen <= (charssent + 896L))
  641.             thisblklen = 128;
  642.         if ( !filbuf(txbuf, thisblklen))
  643.             break;
  644.         if (wcputsec(txbuf, ++sectnum, thisblklen)==ERROR)
  645.             return ERROR;
  646.         charssent += thisblklen;
  647.     }
  648.     fclose(in);
  649.     attempts=0;
  650.     do {
  651.         purgeline();
  652.         sendline(EOT);
  653.         fflush(stdout);
  654.         ++attempts;
  655.     }
  656.         while ((firstch=(readock(Rxtimeout, 1)) != ACK) && attempts < RETRYMAX);
  657.     if (attempts == RETRYMAX) {
  658.         zperr("No ACK on EOT");
  659.         return ERROR;
  660.     }
  661.     else
  662.         return OK;
  663. }
  664.  
  665. wcputsec(buf, sectnum, cseclen)
  666. char *buf;
  667. int sectnum;
  668. int cseclen;    /* data length of this sector to send */
  669. {
  670.     register checksum, wcj;
  671.     register char *cp;
  672.     unsigned oldcrc;
  673.     int firstch;
  674.     int attempts;
  675.  
  676.     firstch=0;    /* part of logic to detect CAN CAN */
  677.  
  678. #ifdef NeXT
  679.     [remote transferProgress:Totsecs*blklen];
  680. #endif
  681.     if (Verbose>2)
  682.         fprintf(stderr, "Sector %3d %2dk\n", Totsecs, Totsecs/8 );
  683.     else if (Verbose>1)
  684.         fprintf(stderr, "\rSector %3d %2dk ", Totsecs, Totsecs/8 );
  685.     for (attempts=0; attempts <= RETRYMAX; attempts++) {
  686.         Lastrx= firstch;
  687.         sendline(cseclen==KSIZE?STX:SOH);
  688.         sendline(sectnum);
  689.         sendline(-sectnum -1);
  690.         oldcrc=checksum=0;
  691.         for (wcj=cseclen,cp=buf; --wcj>=0; ) {
  692.             sendline(*cp);
  693.             oldcrc=updcrc((0377& *cp), oldcrc);
  694.             checksum += *cp++;
  695.         }
  696.         if (Crcflg) {
  697.             oldcrc=updcrc(0,updcrc(0,oldcrc));
  698.             sendline((int)oldcrc>>8);
  699.             sendline((int)oldcrc);
  700.         }
  701.         else
  702.             sendline(checksum);
  703.  
  704.         if (Optiong) {
  705.             firstsec = FALSE; return OK;
  706.         }
  707.         firstch = readock(Rxtimeout, (Noeofseen&§num) ? 2:1);
  708. gotnak:
  709.         switch (firstch) {
  710.         case CAN:
  711.             if(Lastrx == CAN) {
  712. cancan:
  713.                 zperr("Cancelled");  return ERROR;
  714.             }
  715.             break;
  716.         case TIMEOUT:
  717.             zperr("Timeout on sector ACK"); continue;
  718.         case WANTCRC:
  719.             if (firstsec)
  720.                 Crcflg = TRUE;
  721.         case NAK:
  722.             zperr("NAK on sector"); continue;
  723.         case ACK: 
  724.             firstsec=FALSE;
  725.             Totsecs += (cseclen>>7);
  726.             return OK;
  727.         case ERROR:
  728.             zperr("Got burst for sector ACK"); break;
  729.         default:
  730.             zperr("Got %02x for sector ACK", firstch); break;
  731.         }
  732.         for (;;) {
  733.             Lastrx = firstch;
  734.             if ((firstch = readock(Rxtimeout, 2)) == TIMEOUT)
  735.                 break;
  736.             if (firstch == NAK || firstch == WANTCRC)
  737.                 goto gotnak;
  738.             if (firstch == CAN && Lastrx == CAN)
  739.                 goto cancan;
  740.         }
  741.     }
  742.     zperr("Retry Count Exceeded");
  743.     return ERROR;
  744. }
  745.  
  746. /* fill buf with count chars padding with ^Z for CPM */
  747. filbuf(buf, count)
  748. register char *buf;
  749. {
  750.     register c, m;
  751.  
  752.     if ( !Ascii) {
  753.         m = read(fileno(in), buf, count);
  754.         if (m <= 0)
  755.             return 0;
  756.         while (m < count)
  757.             buf[m++] = 032;
  758.         return count;
  759.     }
  760.     m=count;
  761.     if (Lfseen) {
  762.         *buf++ = 012; --m; Lfseen = 0;
  763.     }
  764.     while ((c=getc(in))!=EOF) {
  765.         if (c == 012) {
  766.             *buf++ = 015;
  767.             if (--m == 0) {
  768.                 Lfseen = TRUE; break;
  769.             }
  770.         }
  771.         *buf++ =c;
  772.         if (--m == 0)
  773.             break;
  774.     }
  775.     if (m==count)
  776.         return 0;
  777.     else
  778.         while (--m>=0)
  779.             *buf++ = CPMEOF;
  780.     return count;
  781. }
  782. /* fill buf with count chars */
  783. zfilbuf(buf, count)
  784. register char *buf;
  785. {
  786.     register c, m;
  787.  
  788.     m=count;
  789.     while ((c=getc(in))!=EOF) {
  790.         *buf++ =c;
  791.         if (--m == 0)
  792.             break;
  793.     }
  794.     return (count - m);
  795. }
  796.  
  797. /* VARARGS1 */
  798. vfile(f, a, b, c)
  799. register char *f;
  800. {
  801.     if (Verbose > 2) {
  802.         fprintf(stderr, f, a, b, c);
  803.         fprintf(stderr, "\n");
  804.     }
  805. }
  806.  
  807.  
  808. alrm()
  809. {
  810.     longjmp(tohere, -1);
  811. }
  812.  
  813.  
  814. /*
  815.  * readock(timeout, count) reads character(s) from file descriptor 0
  816.  *  (1 <= count <= 3)
  817.  * it attempts to read count characters. If it gets more than one,
  818.  * it is an error unless all are CAN
  819.  * (otherwise, only normal response is ACK, CAN, or C)
  820.  *  Only looks for one if Optiong, which signifies cbreak, not raw input
  821.  *
  822.  * timeout is in tenths of seconds
  823.  */
  824. readock(timeout, count)
  825. {
  826.     register int c;
  827.     static char byt[5];
  828.  
  829.     if (Optiong)
  830.         count = 1;    /* Special hack for cbreak */
  831.  
  832.     fflush(stdout);
  833.     if (setjmp(tohere)) {
  834.         zperr("TIMEOUT");
  835.         return TIMEOUT;
  836.     }
  837.     c = timeout/10;
  838.     if (c<2)
  839.         c=2;
  840.     if (Verbose>5) {
  841.         fprintf(stderr, "Timeout=%d Calling alarm(%d) ", timeout, c);
  842.         byt[1] = 0;
  843.     }
  844.     signal(SIGALRM, alrm); alarm(c);
  845. #ifdef ONEREAD
  846.     c=read(iofd, byt, 1);        /* regulus raw read is unique */
  847. #else
  848.     c=read(iofd, byt, count);
  849. #endif
  850.     alarm(0);
  851.     if (Verbose>5)
  852.         fprintf(stderr, "ret cnt=%d %x %x\n", c, byt[0], byt[1]);
  853.     if (c<1)
  854.         return TIMEOUT;
  855.     if (c==1)
  856.         return (byt[0]&0377);
  857.     else
  858.         while (c)
  859.             if (byt[--c] != CAN)
  860.                 return ERROR;
  861.     return CAN;
  862. }
  863. readline(n)
  864. {
  865.     return (readock(n, 1));
  866. }
  867.  
  868.  
  869. purgeline()
  870. {
  871. #ifdef USG
  872.     ioctl(iofd, TCFLSH, 0);
  873. #else
  874.     lseek(iofd, 0L, 2);
  875. #endif
  876. }
  877.  
  878.  
  879. /* send cancel string to get the other end to shut up */
  880. canit()
  881. {
  882.     static char canistr[] = {
  883.      24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
  884.     };
  885.  
  886.     printf(canistr);
  887.     fflush(stdout);
  888. }
  889.  
  890. /*
  891.  * Log an error
  892.  */
  893. /*VARARGS1*/
  894. zperr(s,p,u)
  895. char *s, *p, *u;
  896. {
  897.     if (Verbose <= 0)
  898.         return;
  899.     fprintf(stderr, "Retry %d: ", errors);
  900.     fprintf(stderr, s, p, u);
  901.     fprintf(stderr, "\n");
  902. }
  903.  
  904. /*
  905.  * return 1 iff stdout and stderr are different devices
  906.  *  indicating this program operating with a modem on a
  907.  *  different line
  908.  */
  909. from_cu()
  910. {
  911.     struct stat a, b;
  912.     fstat(1, &a); fstat(2, &b);
  913.     return (a.st_rdev != b.st_rdev);
  914. }
  915.  
  916. /*
  917.  * substr(string, token) searches for token in string s
  918.  * returns pointer to token within string if found, NULL otherwise
  919.  */
  920. char *
  921. substr(s, t)
  922. register char *s,*t;
  923. {
  924.     register char *ss,*tt;
  925.     /* search for first char of token */
  926.     for (ss=s; *s; s++)
  927.         if (*s == *t)
  928.             /* compare token with substring */
  929.             for (ss=s,tt=t; ;) {
  930.                 if (*tt == 0)
  931.                     return s;
  932.                 if (*ss++ != *tt++)
  933.                     break;
  934.             }
  935.     return NULL;
  936. }
  937.  
  938. char *babble[] = {
  939.     "Send file(s) with ZMODEM/YMODEM/XMODEM Protocol",
  940.     "    (Y) = Option applies to YMODEM only",
  941.     "    (Z) = Option applies to ZMODEM only",
  942.     "Usage:    sz [-12+abdefkLlNnquvwYy] [-] file ...",
  943.     "    sz [-12Ceqv] -c COMMAND",
  944.     "    sb [-12adfkquv] [-] file ...",
  945.     "    sx [-12akquv] [-] file",
  946.     "    1 Use stdout for modem input",
  947. #ifdef CSTOPB
  948.     "    2 Use 2 stop bits",
  949. #endif
  950.     "    + Append to existing destination file (Z)",
  951.     "    a (ASCII) change NL to CR/LF",
  952.     "    b Binary file transfer override",
  953.     "    c send COMMAND (Z)",
  954.     "    d Change '.' to '/' in pathnames (Y/Z)",
  955.     "    e Escape all control characters (Z)",
  956.     "    f send Full pathname (Y/Z)",
  957.     "    i send COMMAND, ack Immediately (Z)",
  958.     "    k Send 1024 byte packets (Y)",
  959.     "    L N Limit subpacket length to N bytes (Z)",
  960.     "    l N Limit frame length to N bytes (l>=L) (Z)",
  961.     "    n send file if source newer (Z)",
  962.     "    N send file if source newer or longer (Z)",
  963.     "    o Use 16 bit CRC instead of 32 bit CRC (Z)",
  964.     "    p Protect existing destination file (Z)",
  965.     "    r Resume/Recover interrupted file transfer (Z)",
  966.     "    q Quiet (no progress reports)",
  967.     "    u Unlink file after transmission",
  968.     "    v Verbose - provide debugging information",
  969.     "    w N Window is N bytes (Z)",
  970.     "    Y Yes, overwrite existing file, skip if not present at rx (Z)",
  971.     "    y Yes, overwrite existing file (Z)",
  972.     "- as pathname sends standard input as sPID.sz or environment ONAME",
  973.     ""
  974. };
  975.  
  976. usage()
  977. {
  978.     char **pp;
  979.  
  980.     for (pp=babble; **pp; ++pp)
  981.         fprintf(stderr, "%s\n", *pp);
  982.     fprintf(stderr, "%s for %s by Chuck Forsberg  ", VERSION, OS);
  983.     exit(1);
  984. }
  985.  
  986. /*
  987.  * Get the receiver's init parameters
  988.  */
  989. getzrxinit()
  990. {
  991.     register n;
  992.     struct stat f;
  993.  
  994.     for (n=10; --n>=0; ) {
  995.         
  996.         switch (zgethdr(Rxhdr, 1)) {
  997.         case ZCHALLENGE:    /* Echo receiver's challenge numbr */
  998.             stohdr(Rxpos);
  999.             zshhdr(ZACK, Txhdr);
  1000.             continue;
  1001.         case ZCOMMAND:        /* They didn't see out ZRQINIT */
  1002.             stohdr(0L);
  1003.             zshhdr(ZRQINIT, Txhdr);
  1004.             continue;
  1005.         case ZRINIT:
  1006.             Rxflags = 0377 & Rxhdr[ZF0];
  1007.             Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32));
  1008.             Zctlesc |= Rxflags & TESCCTL;
  1009.             Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8);
  1010.             vfile("Rxbuflen=%d Tframlen=%d", Rxbuflen, Tframlen);
  1011.             if ( !Fromcu)
  1012.                 signal(SIGINT, SIG_IGN);
  1013. #ifdef USG
  1014.             mode(2);    /* Set cbreak, XON/XOFF, etc. */
  1015. #endif
  1016. #ifndef READCHECK
  1017. #ifndef USG
  1018.             /* Use 1024 byte frames if no sample/interrupt */
  1019.             if (Rxbuflen < 32 || Rxbuflen > 1024) {
  1020.                 Rxbuflen = 1024;
  1021.                 vfile("Rxbuflen=%d", Rxbuflen);
  1022.             }
  1023. #endif
  1024. #endif
  1025.             /* Override to force shorter frame length */
  1026.             if (Rxbuflen && (Rxbuflen>Tframlen) && (Tframlen>=32))
  1027.                 Rxbuflen = Tframlen;
  1028.             if ( !Rxbuflen && (Tframlen>=32) && (Tframlen<=1024))
  1029.                 Rxbuflen = Tframlen;
  1030.             vfile("Rxbuflen=%d", Rxbuflen);
  1031.  
  1032.             /* If using a pipe for testing set lower buf len */
  1033.             fstat(iofd, &f);
  1034.             if ((f.st_mode & S_IFMT) != S_IFCHR
  1035.               && (Rxbuflen == 0 || Rxbuflen > 4096))
  1036.                 Rxbuflen = 4096;
  1037.             /*
  1038.              * If input is not a regular file, force ACK's each 1024
  1039.              *  (A smarter strategey could be used here ...)
  1040.              */
  1041.             fstat(fileno(in), &f);
  1042.             if (((f.st_mode & S_IFMT) != S_IFREG)
  1043.               && (Rxbuflen == 0 || Rxbuflen > 1024))
  1044.                 Rxbuflen = 1024;
  1045.             vfile("Rxbuflen=%d", Rxbuflen);
  1046.  
  1047.             return (sendzsinit());
  1048.         case ZCAN:
  1049.         case TIMEOUT:
  1050.             return ERROR;
  1051.         case ZRQINIT:
  1052.             if (Rxhdr[ZF0] == ZCOMMAND)
  1053.                 continue;
  1054.         default:
  1055.             zshhdr(ZNAK, Txhdr);
  1056.             continue;
  1057.         }
  1058.     }
  1059.     return ERROR;
  1060. }
  1061.  
  1062. /* Send send-init information */
  1063. sendzsinit()
  1064. {
  1065.     register c;
  1066.  
  1067.     if (Myattn[0] == '\0' && (!Zctlesc || (Rxflags & TESCCTL)))
  1068.         return OK;
  1069.     errors = 0;
  1070.     for (;;) {
  1071.         stohdr(0L);
  1072.         if (Zctlesc) {
  1073.             Txhdr[ZF0] |= TESCCTL; zshhdr(ZSINIT, Txhdr);
  1074.         }
  1075.         else
  1076.             zsbhdr(ZSINIT, Txhdr);
  1077.         zsdata(Myattn, 1+strlen(Myattn), ZCRCW);
  1078.         c = zgethdr(Rxhdr, 1);
  1079.         switch (c) {
  1080.         case ZCAN:
  1081.             return ERROR;
  1082.         case ZACK:
  1083.             return OK;
  1084.         default:
  1085.             if (++errors > 19)
  1086.                 return ERROR;
  1087.             continue;
  1088.         }
  1089.     }
  1090. }
  1091.  
  1092. /* Send file name and related info */
  1093. zsendfile(buf, blen)
  1094. char *buf;
  1095. {
  1096.     register c;
  1097.  
  1098.     for (;;) {
  1099.         Txhdr[ZF0] = Lzconv;    /* file conversion request */
  1100.         Txhdr[ZF1] = Lzmanag;    /* file management request */
  1101.         if (Lskipnocor)
  1102.             Txhdr[ZF1] |= ZMSKNOLOC;
  1103.         Txhdr[ZF2] = Lztrans;    /* file transport request */
  1104.         Txhdr[ZF3] = 0;
  1105.         zsbhdr(ZFILE, Txhdr);
  1106.         zsdata(buf, blen, ZCRCW);
  1107. again:
  1108.         c = zgethdr(Rxhdr, 1);
  1109.         switch (c) {
  1110.         case ZRINIT:
  1111.             while ((c = readline(50)) > 0)
  1112.                 if (c == ZPAD) {
  1113.                     goto again;
  1114.                 }
  1115.             /* **** FALL THRU TO **** */
  1116.         default:
  1117.             continue;
  1118.         case ZCAN:
  1119.         case TIMEOUT:
  1120.         case ZABORT:
  1121.         case ZFIN:
  1122.             return ERROR;
  1123.         case ZSKIP:
  1124.             fclose(in); return c;
  1125.         case ZRPOS:
  1126.             /*
  1127.              * Suppress zcrcw request otherwise triggered by
  1128.              * lastyunc==bytcnt
  1129.              */
  1130.             Lastsync = (bytcnt = Txpos = Rxpos) -1;
  1131.             fseek(in, Rxpos, 0);
  1132.             Dontread = FALSE;
  1133.             return zsendfdata();
  1134.         }
  1135.     }
  1136. }
  1137.  
  1138. /* Send the data in the file */
  1139. zsendfdata()
  1140. {
  1141.     register c, e, n;
  1142.     register newcnt;
  1143.     register long tcount = 0;
  1144.     int junkcount;        /* Counts garbage chars received by TX */
  1145.     static int tleft = 6;    /* Counter for test mode */
  1146.  
  1147.     if (Baudrate > 300)
  1148.         blklen = 256;
  1149.     if (Baudrate > 1200)
  1150.         blklen = 512;
  1151.     if (Baudrate > 2400)
  1152.         blklen = KSIZE;
  1153.     if (Rxbuflen && blklen>Rxbuflen)
  1154.         blklen = Rxbuflen;
  1155.     if (blkopt && blklen > blkopt)
  1156.         blklen = blkopt;
  1157.     vfile("Rxbuflen=%d blklen=%d", Rxbuflen, blklen);
  1158.     vfile("Txwindow = %u Txwspac = %d", Txwindow, Txwspac);
  1159.     Lrxpos = 0;
  1160.     junkcount = 0;
  1161.     Beenhereb4 = FALSE;
  1162. somemore:
  1163.     if (setjmp(intrjmp)) {
  1164. waitack:
  1165.         junkcount = 0;
  1166.         c = getinsync(0);
  1167. gotack:
  1168.         switch (c) {
  1169.         default:
  1170.         case ZCAN:
  1171.             fclose(in);
  1172.             return ERROR;
  1173.         case ZSKIP:
  1174.             fclose(in);
  1175.             return c;
  1176.         case ZACK:
  1177.         case ZRPOS:
  1178.             break;
  1179.         case ZRINIT:
  1180.             return OK;
  1181.         }
  1182. #ifdef READCHECK
  1183.         /*
  1184.          * If the reverse channel can be tested for data,
  1185.          *  this logic may be used to detect error packets
  1186.          *  sent by the receiver, in place of setjmp/longjmp
  1187.          *  rdchk(fdes) returns non 0 if a character is available
  1188.          */
  1189.         while (rdchk(iofd)) {
  1190. #ifdef SVR2
  1191.             switch (checked)
  1192. #else
  1193.             switch (readline(1))
  1194. #endif
  1195.             {
  1196.             case CAN:
  1197.             case ZPAD:
  1198.                 c = getinsync(1);
  1199.                 goto gotack;
  1200.             case XOFF:        /* Wait a while for an XON */
  1201.             case XOFF|0200:
  1202.                 readline(100);
  1203.             }
  1204.         }
  1205. #endif
  1206.     }
  1207.  
  1208.     if ( !Fromcu)
  1209.         signal(SIGINT, onintr);
  1210.     newcnt = Rxbuflen;
  1211.     Txwcnt = 0;
  1212.     stohdr(Txpos);
  1213.     zsbhdr(ZDATA, Txhdr);
  1214.  
  1215.     /*
  1216.      * Special testing mode.  This should force receiver to Attn,ZRPOS
  1217.      *  many times.  Each time the signal should be caught, causing the
  1218.      *  file to be started over from the beginning.
  1219.      */
  1220.     if (Testattn) {
  1221.         if ( --tleft)
  1222.             while (tcount < 20000) {
  1223.                 printf(qbf); fflush(stdout);
  1224.                 tcount += strlen(qbf);
  1225. #ifdef READCHECK
  1226.                 while (rdchk(iofd)) {
  1227. #ifdef SVR2
  1228.                     switch (checked)
  1229. #else
  1230.                     switch (readline(1))
  1231. #endif
  1232.                     {
  1233.                     case CAN:
  1234.                     case ZPAD:
  1235. #ifdef TCFLSH
  1236.                         ioctl(iofd, TCFLSH, 1);
  1237. #endif
  1238.                         goto waitack;
  1239.                     case XOFF:    /* Wait for XON */
  1240.                     case XOFF|0200:
  1241.                         readline(100);
  1242.                     }
  1243.                 }
  1244. #endif
  1245.             }
  1246.         signal(SIGINT, SIG_IGN); canit();
  1247.         sleep(3); purgeline(); mode(0);
  1248.         printf("\nsz: Tcount = %ld\n", tcount);
  1249.         if (tleft) {
  1250.             printf("ERROR: Interrupts Not Caught\n");
  1251.             exit(1);
  1252.         }
  1253.         exit(0);
  1254.     }
  1255.  
  1256.     do {
  1257.         if (Dontread) {
  1258.             n = Lastn;
  1259.         } else {
  1260.             n = zfilbuf(txbuf, blklen);
  1261.             Lastread = Txpos;  Lastn = n;
  1262.         }
  1263.         Dontread = FALSE;
  1264.         if (n < blklen)
  1265.             e = ZCRCE;
  1266.         else if (junkcount > 3)
  1267.             e = ZCRCW;
  1268.         else if (bytcnt == Lastsync)
  1269.             e = ZCRCW;
  1270.         else if (Rxbuflen && (newcnt -= n) <= 0)
  1271.             e = ZCRCW;
  1272.         else if (Txwindow && (Txwcnt += n) >= Txwspac) {
  1273.             Txwcnt = 0;  e = ZCRCQ;
  1274.         }
  1275.         else
  1276.             e = ZCRCG;
  1277. #ifdef NeXT
  1278.         [remote transferProgress:Txpos];
  1279. #endif
  1280.         if (Verbose>1)
  1281.             fprintf(stderr, "\r%7ld ZMODEM%s    ",
  1282.               Txpos, Crc32t?" CRC-32":"");
  1283.         zsdata(txbuf, n, e);
  1284.         bytcnt = Txpos += n;
  1285.         if (e == ZCRCW)
  1286.             goto waitack;
  1287. #ifdef READCHECK
  1288.         /*
  1289.          * If the reverse channel can be tested for data,
  1290.          *  this logic may be used to detect error packets
  1291.          *  sent by the receiver, in place of setjmp/longjmp
  1292.          *  rdchk(fdes) returns non 0 if a character is available
  1293.          */
  1294.         fflush(stdout);
  1295.         while (rdchk(iofd)) {
  1296. #ifdef SVR2
  1297.             switch (checked)
  1298. #else
  1299.             switch (readline(1))
  1300. #endif
  1301.             {
  1302.             case CAN:
  1303.             case ZPAD:
  1304.                 c = getinsync(1);
  1305.                 if (c == ZACK)
  1306.                     break;
  1307. #ifdef TCFLSH
  1308.                 ioctl(iofd, TCFLSH, 1);
  1309. #endif
  1310.                 /* zcrce - dinna wanna starta ping-pong game */
  1311.                 zsdata(txbuf, 0, ZCRCE);
  1312.                 goto gotack;
  1313.             case XOFF:        /* Wait a while for an XON */
  1314.             case XOFF|0200:
  1315.                 readline(100);
  1316.             default:
  1317.                 ++junkcount;
  1318.             }
  1319.         }
  1320. #endif    /* READCHECK */
  1321.         if (Txwindow) {
  1322.             while ((tcount = Txpos - Lrxpos) >= Txwindow) {
  1323.                 vfile("%ld window >= %u", tcount, Txwindow);
  1324.                 if (e != ZCRCQ)
  1325.                     zsdata(txbuf, 0, e = ZCRCQ);
  1326.                 c = getinsync(1);
  1327.                 if (c != ZACK) {
  1328. #ifdef TCFLSH
  1329.                     ioctl(iofd, TCFLSH, 1);
  1330. #endif
  1331.                     zsdata(txbuf, 0, ZCRCE);
  1332.                     goto gotack;
  1333.                 }
  1334.             }
  1335.             vfile("window = %ld", tcount);
  1336.         }
  1337.     } while (n == blklen);
  1338.     if ( !Fromcu)
  1339.         signal(SIGINT, SIG_IGN);
  1340.  
  1341.     for (;;) {
  1342.         stohdr(Txpos);
  1343.         zsbhdr(ZEOF, Txhdr);
  1344.         switch (getinsync(0)) {
  1345.         case ZACK:
  1346.             continue;
  1347.         case ZRPOS:
  1348.             goto somemore;
  1349.         case ZRINIT:
  1350.             return OK;
  1351.         case ZSKIP:
  1352.             fclose(in);
  1353.             return c;
  1354.         default:
  1355.             fclose(in);
  1356.             return ERROR;
  1357.         }
  1358.     }
  1359. }
  1360.  
  1361. /*
  1362.  * Respond to receiver's complaint, get back in sync with receiver
  1363.  */
  1364. getinsync(flag)
  1365. {
  1366.     register c;
  1367.  
  1368.     for (;;) {
  1369.         if (Testattn) {
  1370.             printf("\r\n\n\n***** Signal Caught *****\r\n");
  1371.             Rxpos = 0; c = ZRPOS;
  1372.         } else
  1373.             c = zgethdr(Rxhdr, 0);
  1374.         switch (c) {
  1375.         case ZCAN:
  1376.         case ZABORT:
  1377.         case ZFIN:
  1378.         case TIMEOUT:
  1379.             return ERROR;
  1380.         case ZRPOS:
  1381.             /* ************************************* */
  1382.             /*  If sending to a modem beuufer, you   */
  1383.             /*   might send a break at this point to */
  1384.             /*   dump the modem's buffer.         */
  1385.             if (Lastn >= 0 && Lastread == Rxpos) {
  1386.                 Dontread = TRUE;
  1387.             } else {
  1388.                 clearerr(in);    /* In case file EOF seen */
  1389.                 fseek(in, Rxpos, 0);
  1390.             }
  1391.             bytcnt = Lrxpos = Txpos = Rxpos;
  1392.             if (Lastsync == Rxpos) {
  1393.                 if (++Beenhereb4 > 4)
  1394.                     if (blklen > 256)
  1395.                         blklen /= 2;
  1396.             }
  1397.             Lastsync = Rxpos;
  1398.             return c;
  1399.         case ZACK:
  1400.             Lrxpos = Rxpos;
  1401.             if (flag || Txpos == Rxpos)
  1402.                 return ZACK;
  1403.             continue;
  1404.         case ZRINIT:
  1405.         case ZSKIP:
  1406.             fclose(in);
  1407.             return c;
  1408.         case ERROR:
  1409.         default:
  1410.             zsbhdr(ZNAK, Txhdr);
  1411.             continue;
  1412.         }
  1413.     }
  1414. }
  1415.  
  1416.  
  1417. /* Say "bibi" to the receiver, try to do it cleanly */
  1418. saybibi()
  1419. {
  1420.     for (;;) {
  1421.         stohdr(0L);        /* CAF Was zsbhdr - minor change */
  1422.         zshhdr(ZFIN, Txhdr);    /*  to make debugging easier */
  1423.         switch (zgethdr(Rxhdr, 0)) {
  1424.         case ZFIN:
  1425.             sendline('O'); sendline('O'); flushmo();
  1426.         case ZCAN:
  1427.         case TIMEOUT:
  1428.             return;
  1429.         }
  1430.     }
  1431. }
  1432.  
  1433. /* Local screen character display function */
  1434. bttyout(c)
  1435. {
  1436.     if (Verbose)
  1437.         putc(c, stderr);
  1438. }
  1439.  
  1440. /* Send command and related info */
  1441. zsendcmd(buf, blen)
  1442. char *buf;
  1443. {
  1444.     register c;
  1445.     long cmdnum;
  1446.  
  1447.     cmdnum = getpid();
  1448.     errors = 0;
  1449.     for (;;) {
  1450.         stohdr(cmdnum);
  1451.         Txhdr[ZF0] = Cmdack1;
  1452.         zsbhdr(ZCOMMAND, Txhdr);
  1453.         zsdata(buf, blen, ZCRCW);
  1454. listen:
  1455.         Rxtimeout = 100;        /* Ten second wait for resp. */
  1456.         c = zgethdr(Rxhdr, 1);
  1457.  
  1458.         switch (c) {
  1459.         case ZRINIT:
  1460.             goto listen;    /* CAF 8-21-87 */
  1461.         case ERROR:
  1462.         case TIMEOUT:
  1463.             if (++errors > Cmdtries)
  1464.                 return ERROR;
  1465.             continue;
  1466.         case ZCAN:
  1467.         case ZABORT:
  1468.         case ZFIN:
  1469.         case ZSKIP:
  1470.         case ZRPOS:
  1471.             return ERROR;
  1472.         default:
  1473.             if (++errors > 20)
  1474.                 return ERROR;
  1475.             continue;
  1476.         case ZCOMPL:
  1477.             Exitcode = Rxpos;
  1478.             saybibi();
  1479.             return OK;
  1480.         case ZRQINIT:
  1481.             vfile("******** RZ *******");
  1482.             system("rz");
  1483.             vfile("******** SZ *******");
  1484.             goto listen;
  1485.         }
  1486.     }
  1487. }
  1488.  
  1489. /*
  1490.  * If called as sb use YMODEM protocol
  1491.  */
  1492. chkinvok(s)
  1493. char *s;
  1494. {
  1495.     register char *p;
  1496.  
  1497.     p = s;
  1498.     while (*p == '-')
  1499.         s = ++p;
  1500.     while (*p)
  1501.         if (*p++ == '/')
  1502.             s = p;
  1503.     if (*s == 'v') {
  1504.         Verbose=1; ++s;
  1505.     }
  1506.     Progname = s;
  1507.     if (s[0]=='s' && s[1]=='b') {
  1508.         Nozmodem = TRUE; blklen=KSIZE;
  1509.     }
  1510.     if (s[0]=='s' && s[1]=='x') {
  1511.         Modem2 = TRUE;
  1512.     }
  1513. }
  1514. /* End of sz.c */
  1515.